#-*- coding:utf-8 -*-
'''
Created on 2012-7-11

@author: johnny
'''
import time, copy, logging
import vmd_port
import vnc
from db import databases
import vserver
from utils import pinger
from errors import error

NETCARD_DEFAULT = {
                   "vnet_type": "Virtio ParaVirtual",
                   "pg": "Virtual Machine Network 0",
                   "seq": 1
                   }

VHD_DEFAULT = {
               "vhd_type": "IDE",
               "baseimg": '',
               "del": "no",
               "createvhd": "yes",
               "cache": "none",
               "boot_seq": 1,
               "persistence": "yes",
               "size": 41943040.0
               }

VM_DEFAULT = {
               'hostUuid': '',
               'description': '',
               'bootDevice': 'cdn',
               'storage_path': '',
               'storage_uuid': '',
               'usb_dev_list': [],
               'pci_id': '',
               'pcidevice': [],
               'hd': [],
               'memoryAllocatedInMb': '1024',
               'numVcpusAllocated': '1',
               'netcardAllPara': [],
               'usbip': [],
               'cdrom': 'None',
               'cpu_shares': 'no_limit',
               'autoStart': 'no',
               'localTime': 'yes'
               }


class VMBase(object):
    def __init__(self, name):
        self.cfg = None
        #Indicate weather the vm is created
        self.host = None
        self.storage = None
        self.settled = False
        self.exe = None
        self.query = None
        self.name = name
        self.vnc_proc = None
    
    def initialize(self, host):
        self.host = vserver.create_vserver(host)
        self.query = databases.DBQuery(host, user="postgres")
        
    def set_default_img(self):
        if self.cfg['storage_path']:
            self.hard_drive['baseimg'] = (self.cfg['storage_path'] + "/" +
                                          self.cfg['description'] + "/" +
                                          self.cfg['description'] + ".img")
    
    def add_hd(self, hd=None):
        vhd = copy.deepcopy(VHD_DEFAULT)
        if not hd:   
            vhd['baseimg'] = (self.cfg['storage_path'] + "/" +
                              self.cfg['description'] + "/" +
                              self.cfg['description'] + ".img")
        else:
            vhd.update(hd)
            
        self.cfg['hd'].append(vhd)
    
    def get_hostname(self):
        return self.host.hostname
        
    def add_netcard(self, netcard=None):
        ncd = copy.deepcopy(NETCARD_DEFAULT)
        if netcard:
            ncd.update(netcard)
            
        self.cfg['netcardAllPara'].append(ncd)
        
#    def get_my_baseimg(self):
#        return self.query.get_vm_baseimg(self.name)
    
    def get_vhd(self):
        data = self.query.get_vm_vhd(self.name)
        vhds = []
        for vhd in data:
            dd = copy.deepcopy(vmd_port.VHD)
            dd['boot_seq'] = vhd[2]
            dd['vhd_type'] = vhd[3]
            dd['baseimg'] = vhd[4]
            dd['persistence'] = vhd[7]
            dd['cache'] = vhd[8]
            dd['uuid'] = self.get_storage_uuid()
            vhds.append(dd)
    
    def edit_vhd(self, index, key, value):
        vhd_cfg = self.get_vhd()
        vhd_cfg[index][key] = value
    
    def edit_netcard(self):
        pass
    
    def edit_vm(self):
        pass
    
    def get_storage_path(self):
        if self.cfg['storage_path']:
            return self.cfg['storage_path']
        else:
            return self.query.get_vm_storage("""description='%s'""" % self.name)
    
    def get_storage_uuid(self):
        if self.cfg['storage_uuid']:
            return self.cfg['storage_uuid']
        else:
            mount_path = self.get_storage_path()
            return self.query.get_storageUuid("""mount_path='%s'""" % mount_path)
    
    def get_vmUuid(self):
        if self.query is not None and self.cfg is not None:
            keyword = "description=\'" + self.cfg['description'] + "\'"
            return self.query.get_vmUuid(keyword)
    
    def get_parentUuid(self):
        return self.query.get_hostUuid()
    
    def get_baseimg(self):
        if self.hard_drive['baseimg']:
            return self.hard_drive['baseimg']
        else:
            #Not really logical
            return self.query.get_vm_baseimg(self.name)
    
    def set_cfg(self, key, value):
        if key in self.cfg.keys():
            self.cfg[key] = value
        else:
            print "Invalid key" 
    
    def verify_vm_ip(self):
        if self.ip:
            temp_list = str(self.ip).split('.')
            if '10' != temp_list[0] and '10' != temp_list[1]:
                raise error.TestError("""VM DHCP Failed,
                      IP address is not in range 10.10""")
            
    def is_started(self, has_os=True, timeout=120, err=True):
        """
        has_os: using pre-created img or not, default = True
        timeout: timeout for vm start up, default = 120s
        """
        current = time.time()
        start = time.time()
        endtime = current + timeout
        
        while current < endtime:
            if has_os:
                self.ip = self.query.get_vm_ip(self.cfg['description'])
                
                #IP address verification
                self.verify_vm_ip()
                                
                if pinger.ping(self.ip):
                    return time.time() - start
            else:
                key_str = self.cfg['storage_path']
                result = self.host.run(
                         "ps aux|grep %s" % self.name).stdout.strip()
                if result.find(key_str) >= 0:
                    return True
                
            current = time.time()
            time.sleep(2)
        
        if err:
            raise error.VMStartUpTimeoutError()
        else:
            return False
    
    def is_down(self, timeout=120, err=True):
        if not self.name:
            return
        
        key_str = self.get_storage_path()
        current = time.time()
        endtime = current + timeout
        while current < endtime:
            result = self.host.run(
                    "ps aux|grep %s" % self.name).stdout.strip()
            if result.find(key_str) < 0:
                return True
            current = time.time()
            time.sleep(2)
        if err:
            raise error.VMShutdownTimeoutError()
        else:
            return False
    
    def get_vnc_port(self, timeout=30):
        if self.name:
            current = time.time()
            endtime = current + timeout
            
            while current < endtime:
                port = self.query.get_vnc_port(self.name)
                if port:
                    return port
                current = time.time()
                time.sleep(1)
                
            raise error.CommonError("Get vm vnc port failed!")
        
    def start_vnc(self):
        self.vnc_proc = vnc.start_vnc(self.host.hostname,
                                      self.get_vnc_port())
    def close_vnc(self):
        if self.vnc_proc:
            vnc.stop_vnc(self.vnc_proc)
        else:
            logging.info("The vnc process dose not exist")
             
    def update_cfg(self, cfgs):
        self.cfg.update(cfgs)
    
    def update_vhd(self, vhd, index=0):
        self.cfg['hd'][index].update(vhd)

class VMS(VMBase):
    def __init__(self, name):
        VMBase.__init__(self, name)
        self.cfg = copy.deepcopy(VM_DEFAULT)
        self.cfg['description'] = name
        self.name = name
        self.hard_drive = copy.deepcopy(VHD_DEFAULT)
        self.netcard = copy.deepcopy(NETCARD_DEFAULT)
        
       
    def initialize(self, host, executor):
        super(VMS, self).initialize(host)
        #self.storage = None
        self.exe = executor
        
    def start(self, wth_vnc=True):
        opt_id = 400
        params = {}
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                            'vm', 'VmnoclusterchangeTask')
        self.exe.wait_for_done(m_id, self.host.hostname, 120)
        if wth_vnc:
            self.start_vnc()
    
    def shutdown(self):
        opt_id = 1902
        params = {}
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        self.exe.wait_for_done(m_id, self.host.hostname, 120)
        
    def restart(self):
        opt_id = 1903
        params = {}
        params['parentUuid'] = self.self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        self.exe.wait_for_done(m_id, self.host.hostname, 120)
    
    def poweroff(self):
        opt_id = 401
        params = {}
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                            'vm', 'VmnoclusterchangeTask')
        self.exe.wait_for_done(m_id, self.host.hostname, 120)
    
    def pw_restart(self):
        opt_id = 402
        params = {}
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        self.exe.wait_for_done(m_id, self.host.hostname, 120)
    
    def config_ip(self, ip, mask, gateway, wait=False):
        opt_id = 1905
        
        params = {}
        ipconfig = {
                    'gateway': [gateway,],
                    'ip': [{'netmask': mask, 'address': ip}],
                    }
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        params['vmnetcards'] = [ipconfig,]
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        if wait:
            self.exe.wait_for_done(m_id, self.host.hostname, 120)
        return m_id
            
    def config_dns(self, dns, wait=False):
        opt_id = 1907
        
        params = {}
        
        dnsconfig = {'dns': [dns,]}
        
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        params['vmnetcards'] = [dnsconfig]
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        
        if wait:
            self.exe.wait_for_done(m_id, self.host.hostname, 120)
        return m_id
    
    def config_network(self, ip, mask, gateway, dns, wait=True):
        id2 = self.config_dns(dns)
        id1 = self.config_ip(ip, mask, gateway)
        
        if wait:
            self.exe.wait_for_done(id1, self.host.hostname, 120)
            self.exe.wait_for_done(id2, self.host.hostname, 120)
        return [id1, id2]
        
    def config_hostname(self, name, is_restart="yes", wait=True):
        opt_id = 1911
        
        params = {}
        params['parentUuid'] = self.get_parentUuid()
        params['vmUuid'] = self.get_vmUuid()
        params['storage_path'] = self.get_storage_path()
        params['hostname'] = name
        params['is_restart'] = is_restart
        
        m_id = self.exe.run(opt_id, params, self.host.hostname,
                     'vm', 'VmnoclusterchangeTask')
        
        if wait:
            self.exe.wait_for_done(m_id, self.host.hostname, 120)
            
        return m_id
    